/**
 * Copyright (c) 2011 Basil Shikin, BugStat Project
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.bugstat.gui.wizard;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.text.MaskFormatter;

import net.miginfocom.swing.MigLayout;

import org.bugstat.gui.PropertyTracker;
import org.bugstat.gui.UIStrings;
import org.bugstat.renderers.ReportInformation.ImportantDate;
import org.jdesktop.swingx.JXDatePicker;
import org.pietschy.wizard.PanelWizardStep;

/**
 * This page is used prompt the user for company important dates selection. It has following layout:
 * 
 * <pre>
 *     +------------------------+
 *     | DATES                  | 
 *     |   +----------+------+  |
 *     |   | DATE     | INFO |  |
 *     |   +----------+------+  |
 *     |   | DATE |*| |  I1  |  |
 *     |   | DATE |*| |  I2  |  |
 *     |   +----------+------+  |
 *     |   /ADD/REMOVE/         |
 *     +------------------------+
 * </pre>
 * 
 * @author Basil Shikin
 */
public class SelectImportantDatesPage 
    extends PanelWizardStep
{
    private static final long serialVersionUID = 7164086463195289299L;

    private final PropertyTracker tracker = new PropertyTracker();
    
    private final ImportantDatesTableModel tableModel;

    public SelectImportantDatesPage()
    {
        setName(UIStrings.TEXT_IMPORTANT_DATES_TITLE );
        setSummary(UIStrings.TEXT_IMPORTANT_DATES_SUMMARY);

        final JLabel importantDatesLabel = new JLabel(UIStrings.TEXT_IMPORTANT_DATES + ":");
        
        tableModel = new ImportantDatesTableModel();
        trackTableModel( "bugstat.gui.mainframe.important_dates", tableModel );
        
        final JTable importantDatesTable = new JTable( tableModel );
        importantDatesTable.setRowHeight( 22 );
        importantDatesTable.setDefaultEditor( Date.class, new DateCellEditor() );
        importantDatesTable.setDefaultEditor( String.class, new LabelCellEditor() );
        
        final JScrollPane tableWrapper = new JScrollPane( importantDatesTable );
        
        final JButton addButton = new JButton(UIStrings.TEXT_ADD );
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                tableModel.addNewDate();
            }
        });
        
        final JButton removeButton = new JButton(UIStrings.TEXT_REMOVE);
        removeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e)
            {
                final int selectedRow = importantDatesTable.getSelectedRow();
                if ( selectedRow >= 0 )
                {
                    tableModel.removeDateAtRow( selectedRow );
                }
            }
        });

        final JPanel buttonPanel = new JPanel(new MigLayout("fillx", "push[]5[]0", "0[]0"));
        buttonPanel.add( addButton, "wmin button");
        buttonPanel.add( removeButton, "wmin button");

        setLayout(new MigLayout("fill", "9[grow]9", "9[]5[]7[]9"));
        add( importantDatesLabel, "wrap");
        add( tableWrapper, "grow, wrap");
        add( buttonPanel,  "growx, wrap");

        setComplete(true);
    }

    public List<ImportantDate> getImportantDates()
    {
        return tableModel.getImportantDates();
    }

    private void trackTableModel(final  String prefix, final ImportantDatesTableModel tableModel)
    {
        tableModel.setImportantDates( loadDates( prefix ) );
        tableModel.addTableModelListener( new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e)
            {
                // Save dates to the tracker
                saveDates( prefix, tableModel.getImportantDates() );
            }
        } );
    }

    
    
    private List<ImportantDate> loadDates(String prefix)
    {
        final List<ImportantDate> result = new ArrayList<ImportantDate>();
        
        final String importantDatesString = tracker.get( prefix, "" );
        final String[] importantDatesArray = importantDatesString.split( "\t" );
        
        if ( importantDatesArray.length > 1 && importantDatesArray.length % 2 == 0 )
        {
            for ( int i = 0; i < importantDatesArray.length; i += 2 )
            {
                final String timeString = importantDatesArray[i];
                final long timeLong = Long.parseLong( timeString );
                
                final String label = importantDatesArray[i + 1 ];
                
                result.add( new ImportantDate( new Date( timeLong), label ) );
            }
        }
        
        return result;
    }

    private void saveDates(String prefix, List<ImportantDate> importantDates)
    {
        final StringBuffer importantDatesString = new StringBuffer(); 
        for ( ImportantDate date : importantDates )
        {
            importantDatesString.append( date.getDate().getTime() ).append( '\t' );
            importantDatesString.append( date.getLabel() ).append( '\t' );
        }
        
        tracker.put( prefix, importantDatesString.toString() );
    }

    private static class ImportantDatesTableModel 
        extends AbstractTableModel
    {
        private static final long serialVersionUID = 5168477633329130390L;

        private static final String[] s_columnNames = { UIStrings.TEXT_DATE, UIStrings.TEXT_EVENT };
        
        private List<ImportantDate> dates = new ArrayList<ImportantDate>();
        private Date m_lastEditedDate = new Date();
        
        public int getColumnCount()
        {
            return s_columnNames.length;
        }

        public int getRowCount()
        {
            return dates.size();
        }

        public String getColumnName(int col)
        {
            return s_columnNames[col];
        }

        public Object getValueAt(int row, int col)
        {
            final ImportantDate date = dates.get( row );
            
            if ( col == 0 ) return date.getDate();
            else if ( col == 1 ) return date.getLabel();
            else throw new IllegalArgumentException("Unknown column: " + col );
        }

       
        public Class<?> getColumnClass(int col)
        {
            if ( col == 0 ) return Date.class;
            else if ( col == 1 ) return String.class;
            else throw new IllegalArgumentException("Unknown column: " + col );
        }

        
        public boolean isCellEditable(int row, int col)
        {
            return true;
        }

        public void setValueAt(Object value, int row, int col)
        {
            final ImportantDate date = dates.get( row );
            
            final ImportantDate newDate;
            if ( col == 0 ) newDate = new ImportantDate( (Date)value, date.getLabel() );
            else if ( col == 1 ) newDate = new ImportantDate( date.getDate(), (String)value );
            else throw new IllegalArgumentException("Unknown column: " + col );

            dates.set( dates.indexOf( date), newDate );
            
            m_lastEditedDate = newDate.getDate();
            
            fireTableCellUpdated(row, col);
        }
        
        void addNewDate()
        {
            dates.add( new ImportantDate( m_lastEditedDate, UIStrings.TEXT_CLICK_TO_EDIT ) );
            
            fireTableDataChanged();
        }
        
        void removeDate( final ImportantDate importantDate)
        {
            dates.remove( importantDate );
            
            fireTableDataChanged();
        }
        
        void removeDateAtRow(int row)
        {
            removeDate( dates.get( row ) );
        }
        
        List<ImportantDate> getImportantDates()
        {
            return dates;
        }
        
        void setImportantDates( final List<ImportantDate> dates )
        {
            this.dates.clear();
            this.dates.addAll( dates );
            
            fireTableDataChanged();
        }
    }

    private static class DateCellEditor 
        extends AbstractCellEditor
        implements TableCellEditor
    {
        private static final long serialVersionUID = 1808683673861986885L;
        private final JXDatePicker datePicker;

        public DateCellEditor()
        {
            datePicker = new JXDatePicker();
        }
        

        @Override
        public Object getCellEditorValue()
        {
            return datePicker.getDate();
        }

        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
        {
            datePicker.setDate( (Date)value );
            
            return datePicker;
        }
    }
    
    private static class LabelCellEditor 
        extends DefaultCellEditor
    {
        private static final long serialVersionUID = -4388757075891846759L;

        public LabelCellEditor()
        {
            super( new JFormattedTextField( createFormatter() ) );
        }
        
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column)
        {
            Component result = super.getTableCellEditorComponent(table, value, isSelected, row, column);
            
            if ( UIStrings.TEXT_CLICK_TO_EDIT.equals( value ) )
            {
                delegate.setValue( "" );
            }
            
            return result;
        }
        
        private static MaskFormatter createFormatter()
        {
            try
            {
                return new MaskFormatter("******");
            }
            catch (ParseException e)
            {
                // Should never happen
                return null;
            }
        }
    }

}
